package com.siteseat.common.foundation;

import org.springframework.beans.factory.BeanNameAware;

import com.siteseat.common.exception.InternalException;

/**
 * 
 */
public abstract class Component implements BeanNameAware, IComponent {

  protected ObjectLogger    log    = new ObjectLogger( getClass() );

  private String beanName = "";
  
  private volatile boolean inited = false;

  private long startingTime;
  
  /**
   * 
   *
   *
   */
  protected Component() {
    startingTime = System.nanoTime();
    log.info( "starting" );
  }
  
  /**
   * @param componentMaybe
   */
  public static void ensureInited( Object componentMaybe ) {
    if( componentMaybe instanceof Component ) {
      ( (Component)componentMaybe ).ensureInited();
    }
  }

  /**
   * @param componentMaybe
   */
  public static void ensureNotInited( Object componentMaybe ) {
    if( componentMaybe instanceof Component ) {
      ( (Component)componentMaybe ).ensureNotInited();
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public final boolean isInited() {
    return inited;
  }

  /**
   * Sets the inited
   * 
   * @param inited
   *          the inited to set
   */
  private void setInited( boolean inited ) {
    this.inited = inited;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public final void init() throws Exception { 
    ensureNotInited();
    
    log.info( "initializing" );

    try {
      doInit();

      setInited( true );
      
      postInited();
      
      long startedTime = System.nanoTime();
      log.info( "initialized in " + (startedTime - startingTime) / 1000000.0f + " ms" );
    } catch( Exception e ) {
      log.error( "Failed to initialize", e );
      throw e;
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public final void destroy() throws Exception {
    if( isInited() == false ) {
      log.warn( "Destroy not-yet-initialized component" );
      return;
    }

    log.info( "stopping" );
    
    setInited( false );
    doDestroy();
    
    log.info( "stopped" );
  }

  /**
   * @throws Exception
   */
  protected abstract void doInit() throws Exception;
  
  protected void postInited() throws Exception {}

  protected abstract void doDestroy() throws Exception;

  /**
   * {@inheritDoc}
   */
  @Override
  public void ensureInited() {
    if( isInited() == false ) {
      throw new InternalException( "Not initialized yet" );
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void ensureNotInited() {
    if( isInited() == true ) {
      throw new InternalException( "Duplicated initialization" );
    }
  }

  /**
   * Gets the beanName
   *
   * @return the beanName
   */
  public String getBeanName() {
    return beanName;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    return String.format( "%s@%h", getBeanName(), this );
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setBeanName( String beanName ) {
    this.beanName = beanName;
    this.log.setObjectName( toString() );
  }

}
